#region Copyright Jonathan Quiros

//	
// All rights are reserved. Reproduction or transmission in whole or in 
// part, in any form or by any means, electronic, mechanical or otherwise, 
// is prohibited without the prior written consent of the copyright owner.
//
// Filename: PartiesRepository.cs
//

#endregion

using System;
using System.Linq;
using System.Collections.Generic;
using Ids.Web.Listing;
using Novagoal.Models;
using Novagoal.Models.Utils;
using Novagoal.Repositories.Extensions;

namespace Novagoal.Repositories.Entities
{
    public class PartiesRepository : BaseRepository, IPartiesRepository
    {
        #region CONSTANTS



        #endregion

        #region PROPERTIES

        

        #endregion

        #region PUBLIC METHODS

        public IEnumerable<Party> GetParties(int personId)
        {
            return EntitiesContext.parties_people
                .Where(pp => pp.people.id == personId && pp.parties.tournaments.enabled)
                .Select(pp => pp.parties)
                .Select(CreateParty)
                .ToList();
        }

        public List<RankingEntry> GetPeopleRanking(int partyId)
        {
            var dataList = EntitiesContext.parties_people
                .Where(pp => pp.parties.id == partyId)
                .Select(pp => new
                                  {
                                      Person = pp.people, 
                                      Team = pp.teams, 
                                      TotalPoints = pp.total_points
                                  })
                .ToList();

            return dataList.Select(data => new RankingEntry
                                               {
                                                   Person = CreatePerson(data.Person),
                                                   Team = CreateTeam(data.Team),
                                                   TotalPoints = data.TotalPoints
                                               })
                .OrderByDescending(re => re.TotalPoints)
                .ToList();
        }

        public List<RankingEntry> GetPeopleTournament(int tournamentId)
        {
            var ranking = new List<RankingEntry>();

            var dataList = EntitiesContext.parties_people
                .Where(pp => pp.parties.tournaments.id == tournamentId)
                .Select(pp => new
                                  {
                                      Person = pp.people,
                                      Team = pp.teams,
                                      TotalPoints = pp.total_points
                                  })
                .ToList();

            foreach (var data in dataList.Where(data => !ranking.Any(r => r.Person.Id == data.Person.id)))
            {
                ranking.Add(new RankingEntry
                                {
                                    Person = CreatePerson(data.Person),
                                    Team = CreateTeam(data.Team),
                                    TotalPoints = data.TotalPoints
                                });
            }
            ranking = ranking.OrderByDescending(r => r.TotalPoints).ToList();
            return ranking;
        }

        public List<Party> GetParties(Dictionary<PartyListFilter, string> filterList, PartyListSortField sortField, SortDirectionType sortDirection, int currentPage, int pageSize)
        {
            var qryParties = FilterParties(filterList);

            var users = SortParties(qryParties, sortField, sortDirection)
                .TakePage(currentPage, pageSize)
                .AsEnumerable()
                .Select(CreateParty)
                .ToList();

            return users;
        }

        public int GetTotalParties(Dictionary<PartyListFilter, string> filterList)
        {
            return FilterParties(filterList).Count();
        }

        public List<Person> GetPartyMembers(int partyId)
        {
            return EntitiesContext.parties_people
                .Where(pp => pp.parties.id == partyId)
                .Select(pp => pp.people)
                .Select(CreatePerson)
                .OrderBy(p => p.FirstName)
                .ToList();
        }

        public Party GetParty(int partyId)
        {
            return EntitiesContext.parties
                .Where(p => p.id == partyId)
                .Select(CreateParty)
                .FirstOrDefault();
        }

        public int AddParty(Party party)
        {
            var partyEntity = new parties
                                  {
                                      name = party.Name,
                                      people = EntitiesContext.people.Where(p => p.id == party.CreatedBy.Id).FirstOrDefault(),
                                      tournaments = EntitiesContext.tournaments.Where(t => t.id == party.Tournament.Id).FirstOrDefault(),
                                      created_at = UniversalDate,
                                      updated_at = UniversalDate,
                                      updated_by = party.UpdatedBy
                                  };
            EntitiesContext.AddToparties(partyEntity);
            EntitiesContext.SaveChanges();
            return partyEntity.id;
        }

        public int EditParty(Party party)
        {
            var partyEntity = EntitiesContext.parties.Where(p => p.id == party.Id).FirstOrDefault();
            partyEntity.name = party.Name;
            partyEntity.tournaments = EntitiesContext.tournaments.Where(t => t.id == party.Tournament.Id).FirstOrDefault();
            partyEntity.updated_at = UniversalDate;
            partyEntity.updated_by = party.UpdatedBy;

            EntitiesContext.SaveChanges();
            return partyEntity.id;
        }

        public IEnumerable<int> GetPartiesId()
        {
            return EntitiesContext.parties.Select(p => p.id).ToList();
        }

        public List<Person> GetPeopleNotInParty(int partyId)
        {
            var members = GetPartyMembers(partyId);

            var allPeople = EntitiesContext.users
                .Select(u => u.people)
                .Select(CreatePerson)
                .ToList();

            return allPeople.Where(p => !members.Any(m => m.Id == p.Id))
                .OrderBy(p => p.FirstName)
                .ToList();
        }

        public void AddPartyMember(int personId, int partyId)
        {
            var member = new parties_people
                             {
                                 parties = EntitiesContext.parties.Where(p => p.id == partyId).FirstOrDefault(),
                                 people = EntitiesContext.people.Where(p => p.id == personId).FirstOrDefault(),
                                 total_points = 0
                             };
            EntitiesContext.AddToparties_people(member);
            EntitiesContext.SaveChanges();
        }

        public void SetFavoriteTeam(int partyId, int teamId, int personId)
        {
            var member = EntitiesContext.parties_people
                .Where(pp => pp.parties.id == partyId && pp.people.id == personId)
                .FirstOrDefault();
            if(member != null)
            {
                member.teams = EntitiesContext.teams.Where(t => t.id == teamId).FirstOrDefault();
                EntitiesContext.SaveChanges();
            }
        }

        public Team GetFavoriteTeam(int personId, int partyId)
        {
            return EntitiesContext.parties_people
                .Where(pp => pp.people.id == personId && pp.parties.id == partyId)
                .Select(pp => pp.teams)
                .Select(CreateTeam)
                .FirstOrDefault();
        }

        public void AddMessage(int partyId, int personId, string message)
        {
            var messageEntity = new messages
                                    {
                                        parties = EntitiesContext.parties.Where(p => p.id == partyId).FirstOrDefault(),
                                        people = EntitiesContext.people.Where(p => p.id == personId).FirstOrDefault(),
                                        message = message,
                                        created_at = UniversalDate,
                                        updated_by = personId,
                                        updated_at = UniversalDate
                                    };
            EntitiesContext.AddTomessages(messageEntity);
            EntitiesContext.SaveChanges();
        }

        public List<Message> GetMessages(int partyId)
        {
            return EntitiesContext.messages
                .Where(m => m.parties.id == partyId)
                .Select(CreateMessage)
                .OrderByDescending(m => m.CreatedAt)
                .Take(30)
                .OrderBy(m => m.CreatedAt)
                .ToList();
        }

        #endregion

        #region PRIVATE METHODS

        private IQueryable<parties> FilterParties(Dictionary<PartyListFilter, string> filters)
        {
            var parties = EntitiesContext.parties as IQueryable<parties>;

            if (filters != null)
            {
                if (filters.Keys.Contains(PartyListFilter.Id))
                {
                    int id;
                    if (int.TryParse(filters[PartyListFilter.Id], out id))
                    {
                        return parties.Where(item => item.id == id);
                    }
                }
                if (filters.Keys.Contains(PartyListFilter.Name))
                {
                    var strName = filters[PartyListFilter.Name];
                    parties = parties.Where(item => item.name.Contains(strName));
                }
                if (filters.Keys.Contains(PartyListFilter.Tournament))
                {
                    var strTournament = filters[PartyListFilter.Tournament];
                    parties = parties.Where(item => item.tournaments.name.Contains(strTournament));
                }
                if (filters.Keys.Contains(PartyListFilter.CreatedBy))
                {
                    var strCreated = filters[PartyListFilter.CreatedBy];
                    parties = parties.Where(item => item.people.first_name.Contains(strCreated) || item.people.last_name.Contains(strCreated));
                }
            }

            return parties;
        }

        private static IQueryable<parties> SortParties(IQueryable<parties> query, PartyListSortField sortField, SortDirectionType sortDirection)
        {
            switch (sortField)
            {
                case PartyListSortField.Id:
                    return query.OrderBy(item => item.id, sortDirection);

                case PartyListSortField.Name:
                    return query.OrderBy(item => item.name, sortDirection);

                case PartyListSortField.CreatedBy:
                    return query.OrderBy(item => item.people.first_name, sortDirection);

                case PartyListSortField.Tournament:
                    return query.OrderBy(item => item.tournaments.name, sortDirection);

                case PartyListSortField.Participants:
                    return query.OrderBy(item => item.parties_people.Count, sortDirection);

                case PartyListSortField.CreatedAt:
                    return query.OrderBy(item => item.created_at, sortDirection);

                case PartyListSortField.UpdatedAt:
                    return query.OrderBy(item => item.updated_at, sortDirection);

            }
            return query.OrderByDescending(item => item.id);
        }

        #endregion
    }
}